package com.mason.Interceptor;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mason.EnableOperationLog;
import com.mason.model.OperationLog;
import com.mason.parser.IContentParser;
import com.mason.service.operationlog.OperationLogService;
import com.mason.util.ModifyName;
import com.mason.util.ReflectionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author yunfei.shang
 * @title
 * @date 2018/05/24 11:19
 * @descreption 拦截@EnableOperationLog注解的方法
 * 将具体修改存储到数据库中
 */

@Aspect
@Component
public class ModifyAspect {
    private final static Logger logger = LoggerFactory.getLogger(ModifyAspect.class);
    private OperationLog operationLog = new OperationLog();
    private Object oldObject;
    private Object newObject;
    private Map<String, Object> fieldValues;
    @Resource
    private OperationLogService operationLogService;

    @Before("@annotation(enableOperationLog)")
    public void doBefore(JoinPoint joinPoint, EnableOperationLog enableOperationLog) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Object info = joinPoint.getArgs()[0];
        String[] fields = enableOperationLog.fieldName();
        boolean direct = enableOperationLog.direct();
        operationLog.setMethodName(joinPoint.getTarget().getClass().getName()+"."+joinPoint.getSignature().getName());
        operationLog.setOperator("");
        operationLog.setModifyDate(new Date());
        operationLog.setLaunchUrl(request.getRequestURL().toString());
        operationLog.setModifyContent("");
        operationLog.setLogType(enableOperationLog.name());
        if (ModifyName.UPDATE.equals(enableOperationLog.name()) || ModifyName.DELETE.equals(enableOperationLog.name())) {
            for (String field : fields) {
                fieldValues = new HashMap<>();
                if(direct){
                    fieldValues.put("id", info);
                } else {
                    Object result = ReflectionUtils.getFieldValue(info, field);
                    fieldValues.put(field, result);
                }
            }
            try {
                IContentParser contentParser = (IContentParser) enableOperationLog.parseclass().newInstance();
                oldObject = contentParser.getResult(fieldValues, enableOperationLog, operationLog);
                ObjectMapper mapper = new ObjectMapper();
                operationLog.setOriginData(mapper.writeValueAsString(oldObject));
            } catch (Exception e) {
                logger.error("service加载失败:", e);
            }
        } else {
            if (ModifyName.UPDATE.equals(enableOperationLog.name())) {
                logger.error("id查询失败，无法记录日志");
            }
        }
    }

    @AfterReturning(pointcut = "@annotation(enableOperationLog)", returning = "object")
    public void doAfterReturning(Object object, EnableOperationLog enableOperationLog) {
        if (ModifyName.UPDATE.equals(enableOperationLog.name())) {
            IContentParser contentParser = null;
            try {
                contentParser = (IContentParser) enableOperationLog.parseclass().newInstance();
                newObject = contentParser.getResult(fieldValues, enableOperationLog, null);
            } catch (Exception e) {
                logger.error("service加载失败:", e);
            }
            try {
                List<List<Map<String, Object>>> changelist = ReflectionUtils.compareTwoClass(oldObject, newObject);
                ObjectMapper mapper = new ObjectMapper();
                operationLog.setModifyContent(mapper.writeValueAsString(changelist));
            } catch (Exception e) {
                logger.error("比较异常", e);
            }
        }
        if(operationLog.getModifyContent() != null && operationLog.getModifyContent().compareTo("") != 0){
            operationLogService.insert(operationLog);
        }
    }
}
